<?php
namespace OpenBaidu;

use PHPTool\Rurl\Rurl;

class PanBaidu
{
    private static $defaultSplitSize = 4194304;
    private static $urllist = [
        //用户信息
        'uinfo' => [
            'url' => 'https://pan.baidu.com/rest/2.0/xpan/nas?method=uinfo',
            'method' => 'get'
        ],

        //网盘容量
        'quota' => [
            'url' => 'https://pan.baidu.com/api/quota',
            'method' => 'get'
        ],

        //获取文件列表
        'filelist' => [
            'url' => 'https://pan.baidu.com/rest/2.0/xpan/file?method=list',
            'method' => 'get'
        ],

        //上传三部曲
        'upload_precreate' => [
            'url' => 'https://pan.baidu.com/rest/2.0/xpan/file?method=precreate',
            'method' => 'post',
            'content-type' => 'application/x-www-form-urlencoded'
        ],
        'upload_upload' => [
            'url' => 'https://d.pcs.baidu.com/rest/2.0/pcs/superfile2?method=upload',
            'method' => 'post',
            'content-type' => 'application/x-www-form-urlencoded'
        ],
        'upload_create' => [
            'url' => 'https://pan.baidu.com/rest/2.0/xpan/file?method=create',
            'method' => 'post',
            'content-type' => 'multipart/form-data'
        ],

    ];

    /**
     * @param string $file 上传的文件
     * @param string $panfile 上传到网盘的绝对地址
     */
    public function upload($file, $panfile, $access_token)
    {
        //预上传
        // echo '预上传============='.PHP_EOL;
        $size = 0;
        $block_list = [];
        $isdir = 0;
        if(filetype($file) == 'file')
        {
            $splitinfo = $this->splitFile($file);
            array_walk($splitinfo, function($item) use(&$size, &$block_list){
                array_push($block_list, $item['md5']);
                $size += $item['size'];
            });
        }
        else
        {
            $isdir = 1;
        }
        $block_list = json_encode($block_list);
        $path = $panfile;
        // $path = $panfile;
        $autoinit = 1;
        $rtype = 0;
        $content_md5 = md5_file($file);
        $fp = fopen($file, 'r');
        $check_str = fread($fp, 256*1024);
        fclose($fp);
        $slice_md5 = md5($check_str);
        $body_param = compact('path', 'size', 'isdir', 'autoinit', 'rtype', 'block_list');
        $body_param['content-md5'] = $content_md5;
        $body_param['slice-md5'] = $slice_md5;

        $params['query'] = compact('access_token');
        $params['body'] = http_build_query($body_param);

        $data = $this->upload_precreate($params);
        
        if($data['errno']??0)
        {
            return $data;
        }
        if($data['return_type'] == 2)
        {
            return $data;
        }


        // print_r($data);
        // echo PHP_EOL.'===================='.PHP_EOL;

        // return $data;
        $uploadid = $data['uploadid'];
        // 分片上传
        // echo '分片上传============='.PHP_EOL;
        $fp = fopen($file, 'r');
        for($i = 0; $i<count($splitinfo); $i++)
        {
            $query = [
                'access_token' => $access_token,
                'method' => 'upload',
                'type' => 'tmpfile',
                'path' => $path,
                'uploadid' => $uploadid,
                'partseq' =>$i
            ];

			$section = $this->createSectionFile();
			fseek($fp, $i*$this->getSplitSize());
			file_put_contents($section, fread($fp, $this->getSplitSize()));
            $fileobj = new \CURLFile($section);

            // $fileobj->setMimeType('image/jpeg');
            // $fileobj->setPostFilename('mao.jpg');
            $body = [
                // 'file' => fread($fp, self::getSplitSize())
                'file' => $fileobj
            ];
            $params = compact('query', 'body');
            $data = $this->upload_upload($params);
			unlink($section);
			// print_r($data);
            if($data['errno']??0)
            {
                fclose($fp);
                return $data;
            }
        }
        fclose($fp);

        // echo PHP_EOL.'===================='.PHP_EOL;

        //创建文件
        // echo '创建文件============='.PHP_EOL;
        $query = [
            'access_token' => $access_token
        ];
        $body = http_build_query([
            'path' => $path,
            'size' => $size,
            'isdir' => $isdir,
            'rtype' => $rtype,
            'uploadid' => $uploadid,
			'block_list' => $block_list
        ]);

        $params = compact('query', 'body');
        $data = $this->upload_create($params);
        // echo PHP_EOL.'===================='.PHP_EOL;
        return $data;
    }

    /**
     * 获取分片的大小
     */
    private function getSplitSize()
    {
        return self::$defaultSplitSize;
    }

    /**
     * 文件分片
     * @param string $file 文件
     * @param int $maxsize 分片的大小
     * @return array 各个分片的信息
     */
    private function splitFile($file)
    {
        $maxsize = $this->getSplitSize();
        $fp = fopen($file, 'r');
        $md5list = [];
        for(;;)
        {
            $data = fread($fp, $maxsize);
            if($data == '')
            {
                break;
            }
            $md5 = md5($data);
            $size = strlen($data);

            $md5list[] = compact('md5', 'size');
        }
        
        fclose($fp);
        return $md5list;
    }

	/**
	 * 创建一个临时文（切片）件,用于保存切片
	 */
	private function createSectionFile()
	{
		return tempnam(sys_get_temp_dir(), 'openbaidu_upload_section_');
	}


    public function __call($name, $params)
    {
        if(empty(self::$urllist[$name]))
        {
            throw new \Exception('接口 '.$name.' 不存在');
        }

        if(isset($params['body']) && is_array($params['body']))
        {
            switch(self::$urllist[$name]['content-type']??'')
            {
            case 'application/x-www-form-urlencoded':
                $params['body'] = http_build_query($params['body']);
                break;
            }
        }

        request:
        $res = $this->request(self::$urllist[$name]['url'], self::$urllist[$name]['method'], ...$params);

        if($res->errorNum == 28)
        {
            sleep(5);
            goto request;
        }
        if($res->errorNum != 0)
        {
            throw new \Exception('请求出错了： ' . $res->errorMessage);
        }
        if(!$res->contents)
        {
            goto request;
        }
        $data = json_decode($res->contents, true);
        return $data;
    }

    private function request($url, $method, $params=[])
    {
        $rurl = new Rurl();
        if(isset($params['headers']))
        {
            $rurl->setRequestHeaderArray($params['headers']);
        }
        // $rurl->setRequestHeader('cookie', 'BDUSS=FNSRUxvam5qTDBKfmVMS3dZOVFrLXJSQmZwYXd0WnhTZGR4U3dHfmJSNFFPSWhoRVFBQUFBJCQAAAAAAAAAAAEAAAAm1IwhcXExMjI0NTM0MTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCrYGEQq2BhS;');

        if(isset($params['query']))
        {
            $url = $rurl->setUrlParam($url, $params['query']);
        }

        $bodyparam = $params['body']??'';

        switch($method)
        {
        case 'get':
            $res = $rurl->get($url);
            break;
        case 'post':
            $res = $rurl->post($url, $bodyparam);
            break;
        default:
            throw new \Exception('错误的请求方式 ' . $method);
        }
        $rurl->close();
        return $res;
    }
}

